<template>
  <div class="bpmn-viewer">
    <!-- 工具栏 -->
    <div class="viewer-toolbar">
      <Space :size="8">
        <Button size="small" @click="handleZoomIn">
          <template #icon><PlusOutlined /></template>
          放大
        </Button>
        <Button size="small" @click="handleZoomOut">
          <template #icon><MinusOutlined /></template>
          缩小
        </Button>
        <Button size="small" @click="handleZoomReset">
          <template #icon><FullscreenOutlined /></template>
          适应画布
        </Button>
        <Button size="small" type="primary" @click="handleDownload">
          <template #icon><DownloadOutlined /></template>
          下载
        </Button>
      </Space>
    </div>

    <!-- 查看器容器 -->
    <div ref="canvasRef" class="viewer-canvas" :class="{ 'is-loading': !isReady }"></div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from 'vue';

import { Button, Space, message } from 'ant-design-vue';
import {
  DownloadOutlined,
  FullscreenOutlined,
  MinusOutlined,
  PlusOutlined,
} from '@ant-design/icons-vue';
import BpmnViewer from 'bpmn-js/lib/NavigatedViewer';
// 引入中文翻译
import customTranslate from '../bpmn-designer/customTranslate';

interface Props {
  /** BPMN XML */
  bpmnXml?: string;
  /** 高亮的节点ID列表（当前活动节点） */
  highlightedNodes?: string[];
  /** 已完成的节点ID列表 */
  finishedNodes?: string[];
}

const props = withDefaults(defineProps<Props>(), {
  bpmnXml: '',
  highlightedNodes: () => [],
  finishedNodes: () => [],
});

const canvasRef = ref<HTMLDivElement>();
let viewer: BpmnViewer | null = null;
const isReady = ref(false); // 流程图是否已准备好显示

// 初始化 BPMN 查看器
async function initViewer() {
  if (!canvasRef.value) return;

  viewer = new BpmnViewer({
    container: canvasRef.value,
    // 添加中文翻译模块
    additionalModules: [
      {
        translate: ['value', customTranslate],
      },
    ],
  });

  if (props.bpmnXml) {
    await loadDiagram();
  }
}

// 加载流程图
async function loadDiagram() {
  if (!viewer || !props.bpmnXml) return;

  try {
    isReady.value = false; // 开始加载，隐藏画布

    await viewer.importXML(props.bpmnXml);

    // 延迟适应画布，确保容器已完全渲染
    setTimeout(() => {
      if (!viewer) return;

      // 高亮节点
      highlightNodes();

      // 适应画布
      fitViewport();

      // 适应完成后再显示，避免视觉跳动
      setTimeout(() => {
        isReady.value = true;
      }, 50);
    }, 100);
  } catch (error: any) {
    message.error(`加载流程图失败: ${error.message}`);
    isReady.value = true; // 即使失败也要显示
  }
}

// 适应视口（居中并缩放）
function fitViewport() {
  if (!viewer) return;

  try {
    const canvas = viewer.get('canvas');

    // 获取内部视图框
    const { inner } = canvas.viewbox();

    // 计算中心点
    const center = {
      x: inner.x + inner.width / 2,
      y: inner.y + inner.height / 2,
    };

    // 缩放到合适大小并居中
    canvas.zoom('fit-viewport', center);
  } catch (error) {
    console.error('适应画布失败:', error);
  }
}

// 高亮节点
function highlightNodes() {
  if (!viewer) return;

  const canvas = viewer.get('canvas');

  // 高亮当前活动节点（蓝色）
  props.highlightedNodes.forEach((nodeId) => {
    try {
      canvas.addMarker(nodeId, 'highlight-current');
    } catch (error) {
      // 忽略不存在的节点
    }
  });

  // 标记已完成节点（绿色）
  props.finishedNodes.forEach((nodeId) => {
    try {
      canvas.addMarker(nodeId, 'highlight-finished');
    } catch (error) {
      // 忽略不存在的节点
    }
  });
}

// 清除高亮
function clearHighlights() {
  if (!viewer) return;

  const canvas = viewer.get('canvas');
  const elementRegistry = viewer.get('elementRegistry');

  elementRegistry.forEach((element: any) => {
    canvas.removeMarker(element.id, 'highlight-current');
    canvas.removeMarker(element.id, 'highlight-finished');
  });
}

// 放大
function handleZoomIn() {
  if (!viewer) return;
  const canvas = viewer.get('canvas');
  const currentZoom = canvas.zoom();
  canvas.zoom(currentZoom + 0.1);
}

// 缩小
function handleZoomOut() {
  if (!viewer) return;
  const canvas = viewer.get('canvas');
  const currentZoom = canvas.zoom();
  canvas.zoom(currentZoom - 0.1);
}

// 适应画布
function handleZoomReset() {
  fitViewport();
}

// 下载
async function handleDownload() {
  if (!viewer) return;

  try {
    const { svg } = await viewer.saveSVG();
    const blob = new Blob([svg || ''], { type: 'image/svg+xml' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = 'process-diagram.svg';
    link.click();
    URL.revokeObjectURL(url);
    message.success('下载成功');
  } catch (error: any) {
    message.error(`下载失败: ${error.message}`);
  }
}

// 监听 BPMN XML 变化
watch(
  () => props.bpmnXml,
  () => {
    if (viewer && props.bpmnXml) {
      loadDiagram();
    }
  },
);

// 监听高亮节点变化
watch(
  () => [props.highlightedNodes, props.finishedNodes],
  () => {
    if (viewer) {
      clearHighlights();
      highlightNodes();
    }
  },
  { deep: true },
);

onMounted(() => {
  initViewer();
});

onUnmounted(() => {
  if (viewer) {
    viewer.destroy();
  }
});
</script>

<style scoped>
.bpmn-viewer {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #fafafa;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 6px -1px rgba(0, 0, 0, 0.02),
    0 2px 4px 0 rgba(0, 0, 0, 0.02);
}

.viewer-toolbar {
  padding: 12px 16px;
  background: #fff;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
}

.viewer-canvas {
  flex: 1;
  background: #fff;
  transition: opacity 0.3s ease-in-out;
  position: relative;
}

.viewer-canvas.is-loading {
  opacity: 0;
}
</style>

<style>
/* BPMN.js 样式 */
@import 'bpmn-js/dist/assets/diagram-js.css';
@import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';

/* 自定义高亮样式 */
.highlight-current .djs-visual > :nth-child(1) {
  stroke: #1890ff !important;
  stroke-width: 3px !important;
  fill: #e6f7ff !important;
}

.highlight-finished .djs-visual > :nth-child(1) {
  stroke: #52c41a !important;
  stroke-width: 2px !important;
  fill: #f6ffed !important;
}
</style>

